#!/usr/bin/env python3
"""
RedFire Backend 部署脚本
======================

支持多环境部署的自动化脚本
"""

import os
import sys
import argparse
import subprocess
import time
import json
from pathlib import Path
from typing import Dict, List, Optional

# 添加项目根目录到Python路径
project_root = Path(__file__).parent.parent.parent
sys.path.insert(0, str(project_root))

try:
    from shared.logging.unified_logger import get_logger
    logger = get_logger("deployment", "deploy")
except ImportError:
    import logging
    logging.basicConfig(level=logging.INFO)
    logger = logging.getLogger("deployment")


class RedFireDeployment:
    """RedFire部署管理器"""
    
    def __init__(self, environment: str = "development"):
        self.environment = environment
        self.project_root = Path(__file__).parent.parent.parent
        self.compose_file = self._get_compose_file()
        
    def _get_compose_file(self) -> str:
        """获取对应环境的compose文件"""
        if self.environment == "production":
            return "docker-compose.prod.yml"
        else:
            return "docker-compose.yml"
    
    def check_prerequisites(self) -> bool:
        """检查部署前提条件"""
        logger.info("检查部署前提条件...")
        
        # 检查Docker
        try:
            subprocess.run(["docker", "--version"], check=True, capture_output=True)
            logger.info("✅ Docker已安装")
        except (subprocess.CalledProcessError, FileNotFoundError):
            logger.error("❌ Docker未安装或不可用")
            return False
        
        # 检查Docker Compose
        try:
            subprocess.run(["docker-compose", "--version"], check=True, capture_output=True)
            logger.info("✅ Docker Compose已安装")
        except (subprocess.CalledProcessError, FileNotFoundError):
            logger.error("❌ Docker Compose未安装或不可用")
            return False
        
        # 检查配置文件
        compose_path = self.project_root / self.compose_file
        if not compose_path.exists():
            logger.error(f"❌ 配置文件不存在: {compose_path}")
            return False
        logger.info(f"✅ 配置文件存在: {self.compose_file}")
        
        # 检查环境变量文件(生产环境)
        if self.environment == "production":
            env_file = self.project_root / ".env.prod"
            if not env_file.exists():
                logger.warning(f"⚠️ 生产环境变量文件不存在: {env_file}")
                logger.warning("请确保设置了所有必要的环境变量")
        
        return True
    
    def build_images(self, no_cache: bool = False) -> bool:
        """构建Docker镜像"""
        logger.info("构建Docker镜像...")
        
        try:
            cmd = ["docker-compose", "-f", self.compose_file, "build"]
            if no_cache:
                cmd.append("--no-cache")
            
            result = subprocess.run(
                cmd,
                cwd=self.project_root,
                check=True
            )
            
            logger.info("✅ Docker镜像构建完成")
            return True
            
        except subprocess.CalledProcessError as e:
            logger.error(f"❌ Docker镜像构建失败: {e}")
            return False
    
    def start_infrastructure(self) -> bool:
        """启动基础设施服务"""
        logger.info("启动基础设施服务...")
        
        infra_services = ["postgres", "redis", "rabbitmq"]
        
        try:
            subprocess.run([
                "docker-compose", "-f", self.compose_file, 
                "up", "-d"
            ] + infra_services, cwd=self.project_root, check=True)
            
            logger.info("⏳ 等待基础设施服务启动...")
            time.sleep(20)  # 等待服务启动
            
            # 检查服务健康状态
            if self._check_services_health(infra_services):
                logger.info("✅ 基础设施服务启动成功")
                return True
            else:
                logger.error("❌ 基础设施服务健康检查失败")
                return False
                
        except subprocess.CalledProcessError as e:
            logger.error(f"❌ 基础设施服务启动失败: {e}")
            return False
    
    def deploy_services(self, services: Optional[List[str]] = None) -> bool:
        """部署微服务"""
        if services is None:
            services = [
                "api-gateway",
                "user_service", 
                "trading-service",
                "market-data-service",
                "notification-service",
                "monitoring-service"
            ]
        
        logger.info(f"部署微服务: {', '.join(services)}")
        
        try:
            subprocess.run([
                "docker-compose", "-f", self.compose_file,
                "up", "-d"
            ] + services, cwd=self.project_root, check=True)
            
            logger.info("⏳ 等待微服务启动...")
            time.sleep(30)  # 等待服务启动
            
            # 检查服务健康状态
            if self._check_services_health(services):
                logger.info("✅ 微服务部署成功")
                return True
            else:
                logger.error("❌ 微服务健康检查失败")
                return False
                
        except subprocess.CalledProcessError as e:
            logger.error(f"❌ 微服务部署失败: {e}")
            return False
    
    def start_monitoring(self) -> bool:
        """启动监控服务"""
        logger.info("启动监控服务...")
        
        monitoring_services = ["prometheus", "grafana"]
        
        try:
            subprocess.run([
                "docker-compose", "-f", self.compose_file,
                "up", "-d"
            ] + monitoring_services, cwd=self.project_root, check=True)
            
            logger.info("✅ 监控服务启动成功")
            return True
            
        except subprocess.CalledProcessError as e:
            logger.error(f"❌ 监控服务启动失败: {e}")
            return False
    
    def _check_services_health(self, services: List[str]) -> bool:
        """检查服务健康状态"""
        logger.info("检查服务健康状态...")
        
        for service in services:
            try:
                result = subprocess.run([
                    "docker-compose", "-f", self.compose_file,
                    "ps", "-q", service
                ], cwd=self.project_root, capture_output=True, text=True)
                
                if not result.stdout.strip():
                    logger.error(f"❌ 服务 {service} 未运行")
                    return False
                
                # 检查容器状态
                container_id = result.stdout.strip()
                inspect_result = subprocess.run([
                    "docker", "inspect", "--format", 
                    "{{.State.Health.Status}}", container_id
                ], capture_output=True, text=True)
                
                if inspect_result.returncode == 0:
                    health_status = inspect_result.stdout.strip()
                    if health_status == "healthy":
                        logger.info(f"✅ 服务 {service} 健康")
                    elif health_status == "unhealthy":
                        logger.error(f"❌ 服务 {service} 不健康")
                        return False
                    else:
                        logger.info(f"⏳ 服务 {service} 健康检查中...")
                else:
                    logger.info(f"ℹ️ 服务 {service} 无健康检查配置")
                    
            except subprocess.CalledProcessError as e:
                logger.error(f"❌ 检查服务 {service} 失败: {e}")
                return False
        
        return True
    
    def show_service_status(self):
        """显示服务状态"""
        logger.info("服务状态:")
        
        try:
            result = subprocess.run([
                "docker-compose", "-f", self.compose_file, "ps"
            ], cwd=self.project_root, capture_output=True, text=True)
            
            print(result.stdout)
            
        except subprocess.CalledProcessError as e:
            logger.error(f"❌ 获取服务状态失败: {e}")
    
    def show_service_logs(self, service: Optional[str] = None, follow: bool = False):
        """显示服务日志"""
        try:
            cmd = ["docker-compose", "-f", self.compose_file, "logs"]
            if follow:
                cmd.append("-f")
            if service:
                cmd.append(service)
                
            subprocess.run(cmd, cwd=self.project_root)
            
        except subprocess.CalledProcessError as e:
            logger.error(f"❌ 获取服务日志失败: {e}")
    
    def stop_services(self, services: Optional[List[str]] = None):
        """停止服务"""
        try:
            cmd = ["docker-compose", "-f", self.compose_file, "stop"]
            if services:
                cmd.extend(services)
                
            subprocess.run(cmd, cwd=self.project_root, check=True)
            logger.info("✅ 服务已停止")
            
        except subprocess.CalledProcessError as e:
            logger.error(f"❌ 停止服务失败: {e}")
    
    def cleanup(self, remove_volumes: bool = False):
        """清理资源"""
        try:
            cmd = ["docker-compose", "-f", self.compose_file, "down"]
            if remove_volumes:
                cmd.extend(["-v", "--remove-orphans"])
                
            subprocess.run(cmd, cwd=self.project_root, check=True)
            logger.info("✅ 资源清理完成")
            
        except subprocess.CalledProcessError as e:
            logger.error(f"❌ 资源清理失败: {e}")
    
    def full_deploy(self, build: bool = True, no_cache: bool = False) -> bool:
        """完整部署流程"""
        logger.info(f"开始 {self.environment} 环境完整部署...")
        
        # 1. 检查前提条件
        if not self.check_prerequisites():
            return False
        
        # 2. 构建镜像
        if build:
            if not self.build_images(no_cache):
                return False
        
        # 3. 启动基础设施
        if not self.start_infrastructure():
            return False
        
        # 4. 部署微服务
        if not self.deploy_services():
            return False
        
        # 5. 启动监控
        if not self.start_monitoring():
            logger.warning("⚠️ 监控服务启动失败，但不影响主要服务")
        
        # 6. 显示服务状态
        self.show_service_status()
        
        logger.info("🎉 部署完成!")
        self._show_service_urls()
        
        return True
    
    def _show_service_urls(self):
        """显示服务URL"""
        logger.info("服务访问地址:")
        print("🌐 微服务:")
        print("  - API网关:     http://localhost:8000")
        print("  - 用户服务:     http://localhost:8001")
        print("  - 交易服务:     http://localhost:8002")
        print("  - 市场数据服务: http://localhost:8003")
        print("  - 通知服务:     http://localhost:8004")
        print("  - 监控服务:     http://localhost:8005")
        print("")
        print("📊 监控和管理:")
        print("  - Grafana:     http://localhost:3000 (admin/admin123)")
        print("  - Prometheus:  http://localhost:9090")
        print("  - RabbitMQ:    http://localhost:15672 (redfire/redfire123)")
        print("")
        print("📖 API文档:")
        print("  - API网关文档: http://localhost:8000/docs")
        print("  - 用户服务文档: http://localhost:8001/docs")


def main():
    """主函数"""
    parser = argparse.ArgumentParser(description="RedFire Backend 部署脚本")
    
    parser.add_argument(
        "--environment", "-e",
        choices=["development", "production"],
        default="development",
        help="部署环境"
    )
    
    parser.add_argument(
        "--action", "-a",
        choices=["deploy", "stop", "restart", "status", "logs", "cleanup"],
        default="deploy",
        help="执行动作"
    )
    
    parser.add_argument(
        "--service", "-s",
        help="指定服务名称"
    )
    
    parser.add_argument(
        "--build", "-b",
        action="store_true",
        help="构建镜像"
    )
    
    parser.add_argument(
        "--no-cache",
        action="store_true",
        help="不使用缓存构建"
    )
    
    parser.add_argument(
        "--follow", "-f",
        action="store_true",
        help="跟踪日志输出"
    )
    
    parser.add_argument(
        "--remove-volumes",
        action="store_true",
        help="清理时删除数据卷"
    )
    
    args = parser.parse_args()
    
    # 创建部署器
    deployment = RedFireDeployment(args.environment)
    
    try:
        if args.action == "deploy":
            success = deployment.full_deploy(args.build, args.no_cache)
            sys.exit(0 if success else 1)
            
        elif args.action == "stop":
            services = [args.service] if args.service else None
            deployment.stop_services(services)
            
        elif args.action == "restart":
            services = [args.service] if args.service else None
            deployment.stop_services(services)
            time.sleep(5)
            if args.service:
                deployment.deploy_services([args.service])
            else:
                deployment.full_deploy(False)
                
        elif args.action == "status":
            deployment.show_service_status()
            
        elif args.action == "logs":
            deployment.show_service_logs(args.service, args.follow)
            
        elif args.action == "cleanup":
            deployment.cleanup(args.remove_volumes)
            
    except KeyboardInterrupt:
        logger.info("部署被用户中断")
        sys.exit(1)
    except Exception as e:
        logger.error(f"部署失败: {e}")
        sys.exit(1)


if __name__ == "__main__":
    main()
